﻿using Common.Util;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Common.Type
{
    public class Identifier : IIdentifier
    {
        //private static readonly Logger Log = LogManager.GetCurrentClassLogger();
        #region Properties
        /// <summary>
        /// The Issue ID that can be persisted
        /// </summary>
        public int PersistableID { get; private set; }

        /// <summary>
        /// Id that is displayable
        /// </summary>
        public string DisplayableIdentifier { get; private set; }

        protected virtual string PrependedString { get; private set; }

        #endregion //Properties

        #region Constructors
        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="persistableID">The raw ID that is persist able</param>
        public Identifier(int persistableID)
        {
            PersistableID = persistableID;
            //Calculate the displayable ID
            DisplayableIdentifier = VerhoeffCheckDigit.AppendCheckDigit(persistableID).ToString();
        }

        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="persistableID">The raw ID that is persist able</param>
        public Identifier(string prependedString, int persistableID)
        {
            PersistableID = persistableID;
            PrependedString = prependedString;
            //Calculate the displayable ID
            DisplayableIdentifier = PrependedString + VerhoeffCheckDigit.AppendCheckDigit(persistableID).ToString();
        }

        [Obsolete("Use Identifier(string prependedString, string displayableID) for better error checking")]
        public Identifier(string displayableID)
            : this(null, displayableID)
        {
        }

        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="calculatedImageID">An ID that is displayable </param>
        public Identifier(string prependedString, string displayableID)
        {
            DisplayableIdentifier = displayableID;

            PrependedString = ParseStartingString(displayableID);

            if (
                !String.IsNullOrWhiteSpace(prependedString)
                &&
                !String.IsNullOrWhiteSpace(PrependedString)
                &&
                !String.Equals(prependedString, PrependedString, StringComparison.InvariantCultureIgnoreCase)
                )
            {
                throw new ArgumentException(
                    String.Format(
                        "The Identifier is not valid because the prepending string was not correct - DisplayableIdentifier: {0}; Expected Prepended String: {1};",
                        DisplayableIdentifier,
                        prependedString
                    ));
            }

            if (!String.IsNullOrEmpty(displayableID) && !String.IsNullOrEmpty(PrependedString))
            {
                displayableID = displayableID.Remove(0, PrependedString.Length);
            }

            if (!IsValid(displayableID))
            {
                throw new ArgumentException(
                    String.Format(
                        "The Identifier is not valid - DisplayableIdentifier: {0};",
                        DisplayableIdentifier
                    ));
            }

            //Get the raw id
            //Take out the last digit
            PersistableID = Int32.Parse(displayableID.Substring(0, displayableID.Length - 1));
        }

        private static string ParseStartingString(string displayableID)
        {
            StringBuilder prependedString = new StringBuilder();

            foreach (char charValue in displayableID)
            {
                if (char.IsDigit(charValue))
                {
                    //We're done -- break out
                    break;
                }

                prependedString.Append(charValue);
            }

            return prependedString.ToString();
        }

        #endregion //Constructors

        #region Methods
        /// <summary>
        /// Is the IssueID a valid ID?
        /// </summary>
        /// <param name="calculatedID"></param>
        /// <returns></returns>
        public static bool IsValid(string calculatedID)
        {
            try
            {

                if (string.IsNullOrEmpty(calculatedID))
                {
                    return false;
                }
                //Take out all of the first part of the string

                string startingString = ParseStartingString(calculatedID);

                calculatedID = calculatedID.Remove(0, startingString.Length);

                if (string.IsNullOrEmpty(calculatedID))
                {
                    return false;
                }
                return VerhoeffCheckDigit.Check(calculatedID);
            }
            catch //(FormatException ex)
            {
                //Log.InfoException("Parsing the string {" + calculatedID + "} for the identifier", ex);
                return false;
            }
        }

        /// <summary>
        /// Convert to a string
        /// </summary>
        public override string ToString()
        {
            return DisplayableIdentifier.ToString();
        }
        #endregion //Methods
    }
}
